'''
模拟打印机：
    问题描述：
        平均每天大约10名学生在任何给定时间在实验室工作。平均每人每小时打印2次，这些任务的长度范围从1到20页。打印机每分钟以草稿质量可以处理10页。
        更好的质量每分钟只能处理五页。现在我们考虑学生的平均等待时间，考虑通过一个模拟实验来决定。当学生提交打印任务时，我们将把他们添加到
        等待列表中，一个打印任务的队列。 当打印机完成任务时，它将检查队列，以检查是否有剩余的任务要处理。
    解决思路：
        实际上模拟此问题就是模拟产生队列处理任务时间的概率等。现平均每小时有10*2=20个任务，也就是平均180s大概有一个任务，即每秒产生任务的
        概率为1/180.可以通过随机数产生。每次打印的页数1-20.也可以通过随机数来实现。

        现在创建三个对象。打印机printer,任务task，队列taskqueue
'''

import random
from Queue import Queue

# 按照文档简单实现，后面考虑不同任务要求的打印速度不一样，将该属性放在队列中而不是打印机中.
# 当然也有其他需要考虑的问题，感冒好了之后好好思考！
class Printer:
    def __init__(self,ppm):
        self.pagerate = ppm # 打印速度
        self.currentTask = None # 当前任务
        self.timeRemaining = 0  # 任务需要时间，每个新任务用来递减来判断是否完成

    def tick(self): # 随着时间不断减少本次任务所需时间
        if self.currentTask != None:
            self.timeRemaining = self.timeRemaining - 1
            if self.timeRemaining <= 0:
                self.currentTask = None
    
    def busy(self): # 打印机状态
        if self.currentTask != None:
            return True
        else:
            return False

    def startNext(self,newtask):
        self.currentTask = newtask
        self.timeRemaining = newtask.getPages() * 60/self.pagerate  # 下一个打印时间

class Task:
    def __init__(self,time):
        self.timestamp = time   # 任务加入队列时间
        self.pages = random.randrange(1,21)    # 随机页数

    # 返回任务加入队列时间，任务页数，任务等待时间(传入当前时间)

    def getStamp(self):
        return  self.timestamp

    def getPages(self):
        return  self.pages

    def waitTime(self,currenttime):
        return (currenttime - self.timestamp)

def newPrintTask(): # 创建新任务
    num = random.randrange(1,181)
    if num == 180:
        return True
    else:
        return  False

def simulation(numSeconds,pagesPerMinutes): # 仿真，传入时间(s)和打印速率

        labprinter = Printer(pagesPerMinutes)   # 创建打印机
        printQueue = Queue()    # 打印队列
        waitingtimes = []   # 保留队列每任务等待时间

        for currenttime in range(numSeconds):

            if newPrintTask():  # 是否创建新任务
                task = Task(currenttime)
                printQueue.enqueue(task)

            if(not labprinter.busy()) and (not printQueue.isEmpty()):   # 打印机不忙并且队列不为空，进行下一个任务
                nexttask = printQueue.dequeue() # 返回一个任务并删除
                waitingtimes.append(nexttask.waitTime(currenttime))
                labprinter.startNext(nexttask)
            # 其他情况：打印机不断打印，直到打印完毕
            labprinter.tick()

        averageWait = sum(waitingtimes)/len(waitingtimes)
        print("Average wait time %6.2f secs %3d tasks remaining." %(averageWait,printQueue.size()))

if __name__ == '__main__':
    print("Pagerate is 5: ")
    for i in range(10): # 模拟十次
        simulation(3600,5)
    print("\nPageRate is 10:\n****************************************")
    for i in range(10): # 模拟十次
        simulation(3600,10)



